home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-10-28 | 56.8 KB | 1,519 lines |
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- NNNNAAAAMMMMEEEE
- perlfaq5 - Files and Formats ($Revision: 1.24 $, $Date:
- 1998/07/05 15:07:20 $)
-
- DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- This section deals with I/O and the "f" issues: filehandles,
- flushing, formats, and footers.
-
- HHHHoooowwww ddddoooo IIII fffflllluuuusssshhhh////uuuunnnnbbbbuuuuffffffffeeeerrrr aaaannnn oooouuuuttttppppuuuutttt ffffiiiilllleeeehhhhaaaannnnddddlllleeee???? WWWWhhhhyyyy mmmmuuuusssstttt IIII ddddoooo
- tttthhhhiiiissss????
-
- The C standard I/O library (stdio) normally buffers
- characters sent to devices. This is done for efficiency
- reasons, so that there isn't a system call for each byte.
- Any time you use _p_r_i_n_t() or _w_r_i_t_e() in Perl, you go though
- this buffering. _s_y_s_w_r_i_t_e() circumvents stdio and buffering.
-
- In most stdio implementations, the type of output buffering
- and the size of the buffer varies according to the type of
- device. Disk files are block buffered, often with a buffer
- size of more than 2k. Pipes and sockets are often buffered
- with a buffer size between 1/2 and 2k. Serial devices (e.g.
- modems, terminals) are normally line-buffered, and stdio
- sends the entire line when it gets the newline.
-
- Perl does not support truly unbuffered output (except
- insofar as you can syswrite(OUT, $char, 1)). What it does
- instead support is "command buffering", in which a physical
- write is performed after every output command. This isn't
- as hard on your system as unbuffering, but does get the
- output where you want it when you want it.
-
- If you expect characters to get to your device when you
- print them there, you'll want to autoflush its handle. Use
- _s_e_l_e_c_t() and the $| variable to control autoflushing (see
- the section on $| in the _p_e_r_l_v_a_r manpage and the select
- entry in the _p_e_r_l_f_u_n_c manpage):
-
- $old_fh = select(OUTPUT_HANDLE);
- $| = 1;
- select($old_fh);
-
- Or using the traditional idiom:
-
- select((select(OUTPUT_HANDLE), $| = 1)[0]);
-
- Or if don't mind slowly loading several thousand lines of
- module code just because you're afraid of the $| variable:
-
- use FileHandle;
- open(DEV, "+</dev/tty"); # ceci n'est pas une pipe
- DEV->autoflush(1);
-
-
-
- Page 1 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- or the newer IO::* modules:
-
- use IO::Handle;
- open(DEV, ">/dev/printer"); # but is this?
- DEV->autoflush(1);
-
- or even this:
-
- use IO::Socket; # this one is kinda a pipe?
- $sock = IO::Socket::INET->new(PeerAddr => 'www.perl.com',
- PeerPort => 'http(80)',
- Proto => 'tcp');
- die "$!" unless $sock;
-
- $sock->autoflush();
- print $sock "GET / HTTP/1.0" . "\015\012" x 2;
- $document = join('', <$sock>);
- print "DOC IS: $document\n";
-
- Note the bizarrely hardcoded carriage return and newline in
- their octal equivalents. This is the ONLY way (currently)
- to assure a proper flush on all platforms, including
- Macintosh. That the way things work in network programming:
- you really should specify the exact bit pattern on the
- network line terminator. In practice, "\n\n" often works,
- but this is not portable.
-
- See the _p_e_r_l_f_a_q_9 manpage for other examples of fetching URLs
- over the web.
-
- HHHHoooowwww ddddoooo IIII cccchhhhaaaannnnggggeeee oooonnnneeee lllliiiinnnneeee iiiinnnn aaaa ffffiiiilllleeee////ddddeeeelllleeeetttteeee aaaa lllliiiinnnneeee iiiinnnn aaaa
- ffffiiiilllleeee////iiiinnnnsssseeeerrrrtttt aaaa lllliiiinnnneeee iiiinnnn tttthhhheeee mmmmiiiiddddddddlllleeee ooooffff aaaa ffffiiiilllleeee////aaaappppppppeeeennnndddd ttttoooo tttthhhheeee
- bbbbeeeeggggiiiinnnnnnnniiiinnnngggg ooooffff aaaa ffffiiiilllleeee????
-
- Although humans have an easy time thinking of a text file as
- being a sequence of lines that operates much like a stack of
- playing cards -- or punch cards -- computers usually see the
- text file as a sequence of bytes. In general, there's no
- direct way for Perl to seek to a particular line of a file,
- insert text into a file, or remove text from a file.
-
- (There are exceptions in special circumstances. You can add
- or remove at the very end of the file. Another is replacing
- a sequence of bytes with another sequence of the same
- length. Another is using the $DB_RECNO array bindings as
- documented in the _D_B__F_i_l_e manpage. Yet another is
- manipulating files with all lines the same length.)
-
- The general solution is to create a temporary copy of the
- text file with the changes you want, then copy that over the
- original. This assumes no locking.
-
-
-
-
- Page 2 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- $old = $file;
- $new = "$file.tmp.$$";
- $bak = "$file.bak";
-
- open(OLD, "< $old") or die "can't open $old: $!";
- open(NEW, "> $new") or die "can't open $new: $!";
-
- # Correct typos, preserving case
- while (<OLD>) {
- s/\b(p)earl\b/${1}erl/i;
- (print NEW $_) or die "can't write to $new: $!";
- }
-
- close(OLD) or die "can't close $old: $!";
- close(NEW) or die "can't close $new: $!";
-
- rename($old, $bak) or die "can't rename $old to $bak: $!";
- rename($new, $old) or die "can't rename $new to $old: $!";
-
- Perl can do this sort of thing for you automatically with
- the -i command-line switch or the closely-related $^I
- variable (see the _p_e_r_l_r_u_n manpage for more details). Note
- that -i may require a suffix on some non-Unix systems; see
- the platform-specific documentation that came with your
- port.
-
- # Renumber a series of tests from the command line
- perl -pi -e 's/(^\s+test\s+)\d+/ $1 . ++$count /e' t/op/taint.t
-
- # form a script
- local($^I, @ARGV) = ('.bak', glob("*.c"));
- while (<>) {
- if ($. == 1) {
- print "This line should appear at the top of each file\n";
- }
- s/\b(p)earl\b/${1}erl/i; # Correct typos, preserving case
- print;
- close ARGV if eof; # Reset $.
- }
-
- If you need to seek to an arbitrary line of a file that
- changes infrequently, you could build up an index of byte
- positions of where the line ends are in the file. If the
- file is large, an index of every tenth or hundredth line end
- would allow you to seek and read fairly efficiently. If the
- file is sorted, try the look.pl library (part of the
- standard perl distribution).
-
- In the unique case of deleting lines at the end of a file,
- you can use _t_e_l_l() and _t_r_u_n_c_a_t_e(). The following code
- snippet deletes the last line of a file without making a
- copy or reading the whole file into memory:
-
-
-
- Page 3 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- open (FH, "+< $file");
- while ( <FH> ) { $addr = tell(FH) unless eof(FH) }
- truncate(FH, $addr);
-
- Error checking is left as an exercise for the reader.
-
- HHHHoooowwww ddddoooo IIII ccccoooouuuunnnntttt tttthhhheeee nnnnuuuummmmbbbbeeeerrrr ooooffff lllliiiinnnneeeessss iiiinnnn aaaa ffffiiiilllleeee????
-
- One fairly efficient way is to count newlines in the file.
- The following program uses a feature of tr///, as documented
- in the _p_e_r_l_o_p manpage. If your text file doesn't end with a
- newline, then it's not really a proper text file, so this
- may report one fewer line than you expect.
-
- $lines = 0;
- open(FILE, $filename) or die "Can't open `$filename': $!";
- while (sysread FILE, $buffer, 4096) {
- $lines += ($buffer =~ tr/\n//);
- }
- close FILE;
-
- This assumes no funny games with newline translations.
-
- HHHHoooowwww ddddoooo IIII mmmmaaaakkkkeeee aaaa tttteeeemmmmppppoooorrrraaaarrrryyyy ffffiiiilllleeee nnnnaaaammmmeeee????
-
- Use the new_tmpfile class method from the IO::File module to
- get a filehandle opened for reading and writing. Use this
- if you don't need to know the file's name.
-
- use IO::File;
- $fh = IO::File->new_tmpfile()
- or die "Unable to make new temporary file: $!";
-
- Or you can use the tmpnam function from the POSIX module to
- get a filename that you then open yourself. Use this if you
- do need to know the file's name.
-
- use Fcntl;
- use POSIX qw(tmpnam);
-
- # try new temporary filenames until we get one that didn't already
- # exist; the check should be unnecessary, but you can't be too careful
- do { $name = tmpnam() }
- until sysopen(FH, $name, O_RDWR|O_CREAT|O_EXCL);
-
- # install atexit-style handler so that when we exit or die,
- # we automatically delete this temporary file
- END { unlink($name) or die "Couldn't unlink $name : $!" }
-
- # now go on to use the file ...
-
- If you're committed to doing this by hand, use the process
-
-
-
- Page 4 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- ID and/or the current time-value. If you need to have many
- temporary files in one process, use a counter:
-
- BEGIN {
- use Fcntl;
- my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
- my $base_name = sprintf("%s/%d-%d-0000", $temp_dir, $$, time());
- sub temp_file {
- local *FH;
- my $count = 0;
- until (defined(fileno(FH)) || $count++ > 100) {
- $base_name =~ s/-(\d+)$/"-" . (1 + $1)/e;
- sysopen(FH, $base_name, O_WRONLY|O_EXCL|O_CREAT);
- }
- if (defined(fileno(FH))
- return (*FH, $base_name);
- } else {
- return ();
- }
- }
- }
-
-
- HHHHoooowwww ccccaaaannnn IIII mmmmaaaannnniiiippppuuuullllaaaatttteeee ffffiiiixxxxeeeedddd----rrrreeeeccccoooorrrrdddd----lllleeeennnnggggtttthhhh ffffiiiilllleeeessss????
-
- The most efficient way is using _p_a_c_k() and _u_n_p_a_c_k(). This
- is faster than using _s_u_b_s_t_r() when take many, many strings.
- It is slower for just a few.
-
- Here is a sample chunk of code to break up and put back
- together again some fixed-format input lines, in this case
- from the output of a normal, Berkeley-style ps:
-
- # sample input line:
- # 15158 p5 T 0:00 perl /home/tchrist/scripts/now-what
- $PS_T = 'A6 A4 A7 A5 A*';
- open(PS, "ps|");
- print scalar <PS>;
- while (<PS>) {
- ($pid, $tt, $stat, $time, $command) = unpack($PS_T, $_);
- for $var (qw!pid tt stat time command!) {
- print "$var: <$$var>\n";
- }
- print 'line=', pack($PS_T, $pid, $tt, $stat, $time, $command),
- "\n";
- }
-
- We've used $$var in a way that forbidden by use strict
- 'refs'. That is, we've promoted a string to a scalar
- variable reference using symbolic references. This is ok in
- small programs, but doesn't scale well. It also only works
- on global variables, not lexicals.
-
-
-
- Page 5 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- HHHHoooowwww ccccaaaannnn IIII mmmmaaaakkkkeeee aaaa ffffiiiilllleeeehhhhaaaannnnddddlllleeee llllooooccccaaaallll ttttoooo aaaa ssssuuuubbbbrrrroooouuuuttttiiiinnnneeee???? HHHHoooowwww ddddoooo IIII
- ppppaaaassssssss ffffiiiilllleeeehhhhaaaannnnddddlllleeeessss bbbbeeeettttwwwweeeeeeeennnn ssssuuuubbbbrrrroooouuuuttttiiiinnnneeeessss???? HHHHoooowwww ddddoooo IIII mmmmaaaakkkkeeee aaaannnn
- aaaarrrrrrrraaaayyyy ooooffff ffffiiiilllleeeehhhhaaaannnnddddlllleeeessss????
-
- The fastest, simplest, and most direct way is to localize
- the typeglob of the filehandle in question:
-
- local *TmpHandle;
-
- Typeglobs are fast (especially compared with the
- alternatives) and reasonably easy to use, but they also have
- one subtle drawback. If you had, for example, a function
- named _T_m_p_H_a_n_d_l_e(), or a variable named %TmpHandle, you just
- hid it from yourself.
-
- sub findme {
- local *HostFile;
- open(HostFile, "</etc/hosts") or die "no /etc/hosts: $!";
- local $_; # <- VERY IMPORTANT
- while (<HostFile>) {
- print if /\b127\.(0\.0\.)?1\b/;
- }
- # *HostFile automatically closes/disappears here
- }
-
- Here's how to use this in a loop to open and store a bunch
- of filehandles. We'll use as values of the hash an ordered
- pair to make it easy to sort the hash in insertion order.
-
- @names = qw(motd termcap passwd hosts);
- my $i = 0;
- foreach $filename (@names) {
- local *FH;
- open(FH, "/etc/$filename") || die "$filename: $!";
- $file{$filename} = [ $i++, *FH ];
- }
-
- # Using the filehandles in the array
- foreach $name (sort { $file{$a}[0] <=> $file{$b}[0] } keys %file) {
- my $fh = $file{$name}[1];
- my $line = <$fh>;
- print "$name $. $line";
- }
-
- For passing filehandles to functions, the easiest way is to
- prefer them with a star, as in _f_u_n_c(*STDIN). See the
- section on _P_a_s_s_i_n_g _F_i_l_e_h_a_n_d_l_e_s in the _p_e_r_l_f_a_q_7 manpage for
- details.
-
- If you want to create many, anonymous handles, you should
- check out the Symbol, FileHandle, or IO::Handle (etc.)
- modules. Here's the equivalent code with Symbol::gensym,
-
-
-
- Page 6 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- which is reasonably light-weight:
-
- foreach $filename (@names) {
- use Symbol;
- my $fh = gensym();
- open($fh, "/etc/$filename") || die "open /etc/$filename: $!";
- $file{$filename} = [ $i++, $fh ];
- }
-
- Or here using the semi-object-oriented FileHandle, which
- certainly isn't light-weight:
-
- use FileHandle;
-
- foreach $filename (@names) {
- my $fh = FileHandle->new("/etc/$filename") or die "$filename: $!";
- $file{$filename} = [ $i++, $fh ];
- }
-
- Please understand that whether the filehandle happens to be
- a (probably localized) typeglob or an anonymous handle from
- one of the modules, in no way affects the bizarre rules for
- managing indirect handles. See the next question.
-
- HHHHoooowwww ccccaaaannnn IIII uuuusssseeee aaaa ffffiiiilllleeeehhhhaaaannnnddddlllleeee iiiinnnnddddiiiirrrreeeeccccttttllllyyyy????
-
- An indirect filehandle is using something other than a
- symbol in a place that a filehandle is expected. Here are
- ways to get those:
-
- $fh = SOME_FH; # bareword is strict-subs hostile
- $fh = "SOME_FH"; # strict-refs hostile; same package only
- $fh = *SOME_FH; # typeglob
- $fh = \*SOME_FH; # ref to typeglob (bless-able)
- $fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob
-
- Or to use the new method from the FileHandle or IO modules
- to create an anonymous filehandle, store that in a scalar
- variable, and use it as though it were a normal filehandle.
-
- use FileHandle;
- $fh = FileHandle->new();
-
- use IO::Handle; # 5.004 or higher
- $fh = IO::Handle->new();
-
- Then use any of those as you would a normal filehandle.
- Anywhere that Perl is expecting a filehandle, an indirect
- filehandle may be used instead. An indirect filehandle is
- just a scalar variable that contains a filehandle.
- Functions like print, open, seek, or the functions or the
- <FH> diamond operator will accept either a read filehandle
-
-
-
- Page 7 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- or a scalar variable containing one:
-
- ($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);
- print $ofh "Type it: ";
- $got = <$ifh>
- print $efh "What was that: $got";
-
- Of you're passing a filehandle to a function, you can write
- the function in two ways:
-
- sub accept_fh {
- my $fh = shift;
- print $fh "Sending to indirect filehandle\n";
- }
-
- Or it can localize a typeglob and use the filehandle
- directly:
-
- sub accept_fh {
- local *FH = shift;
- print FH "Sending to localized filehandle\n";
- }
-
- Both styles work with either objects or typeglobs of real
- filehandles. (They might also work with strings under some
- circumstances, but this is risky.)
-
- accept_fh(*STDOUT);
- accept_fh($handle);
-
- In the examples above, we assigned the filehandle to a
- scalar variable before using it. That is because only
- simple scalar variables, not expressions or subscripts into
- hashes or arrays, can be used with built-ins like print,
- printf, or the diamond operator. These are illegal and
- won't even compile:
-
- @fd = (*STDIN, *STDOUT, *STDERR);
- print $fd[1] "Type it: "; # WRONG
- $got = <$fd[0]> # WRONG
- print $fd[2] "What was that: $got"; # WRONG
-
- With print and printf, you get around this by using a block
- and an expression where you would place the filehandle:
-
- print { $fd[1] } "funny stuff\n";
- printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
- # Pity the poor deadbeef.
-
- That block is a proper block like any other, so you can put
- more complicated code there. This sends the message out to
- one of two places:
-
-
-
- Page 8 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- $ok = -x "/bin/cat";
- print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n";
- print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";
-
- This approach of treating print and printf like object
- methods calls doesn't work for the diamond operator. That's
- because it's a real operator, not just a function with a
- comma-less argument. Assuming you've been storing typeglobs
- in your structure as we did above, you can use the built-in
- function named readline to reads a record just as <> does.
- Given the initialization shown above for @fd, this would
- work, but only because _r_e_a_d_l_i_n_e() require a typeglob. It
- doesn't work with objects or strings, which might be a bug
- we haven't fixed yet.
-
- $got = readline($fd[0]);
-
- Let it be noted that the flakiness of indirect filehandles
- is not related to whether they're strings, typeglobs,
- objects, or anything else. It's the syntax of the
- fundamental operators. Playing the object game doesn't help
- you at all here.
-
- HHHHoooowwww ccccaaaannnn IIII sssseeeetttt uuuupppp aaaa ffffooooooootttteeeerrrr ffffoooorrrrmmmmaaaatttt ttttoooo bbbbeeee uuuusssseeeedddd wwwwiiiitttthhhh _w_r_i_t_e()?
-
- There's no builtin way to do this, but the _p_e_r_l_f_o_r_m manpage
- has a couple of techniques to make it possible for the
- intrepid hacker.
-
- HHHHoooowwww ccccaaaannnn IIII _w_r_i_t_e() into a string?
-
- See the _p_e_r_l_f_o_r_m manpage for an _s_w_r_i_t_e() function.
-
- HHHHoooowwww ccccaaaannnn IIII oooouuuuttttppppuuuutttt mmmmyyyy nnnnuuuummmmbbbbeeeerrrrssss wwwwiiiitttthhhh ccccoooommmmmmmmaaaassss aaaaddddddddeeeedddd????
-
- This one will do it for you:
-
- sub commify {
- local $_ = shift;
- 1 while s/^(-?\d+)(\d{3})/$1,$2/;
- return $_;
- }
-
- $n = 23659019423.2331;
- print "GOT: ", commify($n), "\n";
-
- GOT: 23,659,019,423.2331
-
- You can't just:
-
- s/^(-?\d+)(\d{3})/$1,$2/g;
-
-
-
-
- Page 9 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- because you have to put the comma in and then recalculate
- your position.
-
- Alternatively, this commifies all numbers in a line
- regardless of whether they have decimal portions, are
- preceded by + or -, or whatever:
-
- # from Andrew Johnson <ajohnson@gpu.srv.ualberta.ca>
- sub commify {
- my $input = shift;
- $input = reverse $input;
- $input =~ s<(\d\d\d)(?=\d)(?!\d*\.)><$1,>g;
- return reverse $input;
- }
-
-
- HHHHoooowwww ccccaaaannnn IIII ttttrrrraaaannnnssssllllaaaatttteeee ttttiiiillllddddeeeessss ((((~~~~)))) iiiinnnn aaaa ffffiiiilllleeeennnnaaaammmmeeee????
-
- Use the <> (_g_l_o_b()) operator, documented in the _p_e_r_l_f_u_n_c
- manpage. This requires that you have a shell installed that
- groks tildes, meaning csh or tcsh or (some versions of) ksh,
- and thus may have portability problems. The Glob::KGlob
- module (available from CPAN) gives more portable glob
- functionality.
-
- Within Perl, you may use this directly:
-
- $filename =~ s{
- ^ ~ # find a leading tilde
- ( # save this in $1
- [^/] # a non-slash character
- * # repeated 0 or more times (0 means me)
- )
- }{
- $1
- ? (getpwnam($1))[7]
- : ( $ENV{HOME} || $ENV{LOGDIR} )
- }ex;
-
-
- HHHHoooowwww ccccoooommmmeeee wwwwhhhheeeennnn IIII ooooppppeeeennnn aaaa ffffiiiilllleeee rrrreeeeaaaadddd----wwwwrrrriiiitttteeee iiiitttt wwwwiiiippppeeeessss iiiitttt oooouuuutttt????
-
- Because you're using something like this, which truncates
- the file and _t_h_e_n gives you read-write access:
-
- open(FH, "+> /path/name"); # WRONG (almost always)
-
- Whoops. You should instead use this, which will fail if the
- file doesn't exist. Using ">" always clobbers or creates.
- Using "<" never does either. The "+" doesn't change this.
-
- Here are examples of many kinds of file opens. Those using
-
-
-
- Page 10 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- _s_y_s_o_p_e_n() all assume
-
- use Fcntl;
-
- To open file for reading:
-
- open(FH, "< $path") || die $!;
- sysopen(FH, $path, O_RDONLY) || die $!;
-
- To open file for writing, create new file if needed or else
- truncate old file:
-
- open(FH, "> $path") || die $!;
- sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT) || die $!;
- sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666) || die $!;
-
- To open file for writing, create new file, file must not
- exist:
-
- sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT) || die $!;
- sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT, 0666) || die $!;
-
- To open file for appending, create if necessary:
-
- open(FH, ">> $path") || die $!;
- sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT) || die $!;
- sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT, 0666) || die $!;
-
- To open file for appending, file must exist:
-
- sysopen(FH, $path, O_WRONLY|O_APPEND) || die $!;
-
- To open file for update, file must exist:
-
- open(FH, "+< $path") || die $!;
- sysopen(FH, $path, O_RDWR) || die $!;
-
- To open file for update, create file if necessary:
-
- sysopen(FH, $path, O_RDWR|O_CREAT) || die $!;
- sysopen(FH, $path, O_RDWR|O_CREAT, 0666) || die $!;
-
- To open file for update, file must not exist:
-
- sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT) || die $!;
- sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT, 0666) || die $!;
-
- To open a file without blocking, creating if necessary:
-
- sysopen(FH, "/tmp/somefile", O_WRONLY|O_NDELAY|O_CREAT)
- or die "can't open /tmp/somefile: $!":
-
-
-
-
- Page 11 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- Be warned that neither creation nor deletion of files is
- guaranteed to be an atomic operation over NFS. That is, two
- processes might both successful create or unlink the same
- file! Therefore O_EXCL isn't so exclusive as you might
- wish.
-
- WWWWhhhhyyyy ddddoooo IIII ssssoooommmmeeeettttiiiimmmmeeeessss ggggeeeetttt aaaannnn """"AAAArrrrgggguuuummmmeeeennnntttt lllliiiisssstttt ttttoooooooo lllloooonnnngggg"""" wwwwhhhheeeennnn IIII
- uuuusssseeee <<<<****>>>>????
-
- The <> operator performs a globbing operation (see above).
- By default _g_l_o_b() forks _c_s_h(1) to do the actual glob
- expansion, but csh can't handle more than 127 items and so
- gives the error message Argument list too long. People who
- installed tcsh as csh won't have this problem, but their
- users may be surprised by it.
-
- To get around this, either do the glob yourself with
- Dirhandles and patterns, or use a module like Glob::KGlob,
- one that doesn't use the shell to do globbing.
-
- IIIIssss tttthhhheeeerrrreeee aaaa lllleeeeaaaakkkk////bbbbuuuugggg iiiinnnn _g_l_o_b()?
-
- Due to the current implementation on some operating systems,
- when you use the _g_l_o_b() function or its angle-bracket alias
- in a scalar context, you may cause a leak and/or
- unpredictable behavior. It's best therefore to use _g_l_o_b()
- only in list context.
-
- HHHHoooowwww ccccaaaannnn IIII ooooppppeeeennnn aaaa ffffiiiilllleeee wwwwiiiitttthhhh aaaa lllleeeeaaaaddddiiiinnnngggg """">>>>"""" oooorrrr ttttrrrraaaaiiiilllliiiinnnngggg bbbbllllaaaannnnkkkkssss????
-
- Normally perl ignores trailing blanks in filenames, and
- interprets certain leading characters (or a trailing "|") to
- mean something special. To avoid this, you might want to
- use a routine like this. It makes incomplete pathnames into
- explicit relative ones, and tacks a trailing null byte on
- the name to make perl leave it alone:
-
- sub safe_filename {
- local $_ = shift;
- return m#^/#
- ? "$_\0"
- : "./$_\0";
- }
-
- $fn = safe_filename("<<<something really wicked ");
- open(FH, "> $fn") or "couldn't open $fn: $!";
-
- You could also use the _s_y_s_o_p_e_n() function (see the sysopen
- entry in the _p_e_r_l_f_u_n_c manpage).
-
-
-
-
-
-
- Page 12 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- HHHHoooowwww ccccaaaannnn IIII rrrreeeelllliiiiaaaabbbbllllyyyy rrrreeeennnnaaaammmmeeee aaaa ffffiiiilllleeee????
-
- Well, usually you just use Perl's _r_e_n_a_m_e() function. But
- that may not work everywhere, in particular, renaming files
- across file systems. If your operating system supports a
- _m_v(1) program or its moral equivalent, this works:
-
- rename($old, $new) or system("mv", $old, $new);
-
- It may be more compelling to use the File::Copy module
- instead. You just copy to the new file to the new name
- (checking return values), then delete the old one. This
- isn't really the same semantics as a real _r_e_n_a_m_e(), though,
- which preserves metainformation like permissions,
- timestamps, inode info, etc.
-
- The newer version of File::Copy export a _m_o_v_e() function.
-
- HHHHoooowwww ccccaaaannnn IIII lllloooocccckkkk aaaa ffffiiiilllleeee????
-
- Perl's builtin _f_l_o_c_k() function (see the _p_e_r_l_f_u_n_c manpage
- for details) will call _f_l_o_c_k(2) if that exists, _f_c_n_t_l(2) if
- it doesn't (on perl version 5.004 and later), and _l_o_c_k_f(3)
- if neither of the two previous system calls exists. On some
- systems, it may even use a different form of native locking.
- Here are some gotchas with Perl's _f_l_o_c_k():
-
- 1 Produces a fatal error if none of the three system calls
- (or their close equivalent) exists.
-
- 2 _l_o_c_k_f(3) does not provide shared locking, and requires
- that the filehandle be open for writing (or appending,
- or read/writing).
-
- 3 Some versions of _f_l_o_c_k() can't lock files over a network
- (e.g. on NFS file systems), so you'd need to force the
- use of _f_c_n_t_l(2) when you build Perl. See the flock
- entry of the _p_e_r_l_f_u_n_c manpage, and the _I_N_S_T_A_L_L file in
- the source distribution for information on building Perl
- to do this.
-
- WWWWhhhhaaaatttt ccccaaaannnn''''tttt IIII jjjjuuuusssstttt _o_p_e_n(FH, ">file.lock")?
-
- A common bit of code NNNNOOOOTTTT TTTTOOOO UUUUSSSSEEEE is this:
-
- sleep(3) while -e "file.lock"; # PLEASE DO NOT USE
- open(LCK, "> file.lock"); # THIS BROKEN CODE
-
- This is a classic race condition: you take two steps to do
- something which must be done in one. That's why computer
- hardware provides an atomic test-and-set instruction. In
- theory, this "ought" to work:
-
-
-
- Page 13 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- sysopen(FH, "file.lock", O_WRONLY|O_EXCL|O_CREAT)
- or die "can't open file.lock: $!":
-
- except that lamentably, file creation (and deletion) is not
- atomic over NFS, so this won't work (at least, not every
- time) over the net. Various schemes involving involving
- _l_i_n_k() have been suggested, but these tend to involve busy-
- wait, which is also subdesirable.
-
- IIII ssssttttiiiillllllll ddddoooonnnn''''tttt ggggeeeetttt lllloooocccckkkkiiiinnnngggg.... IIII jjjjuuuusssstttt wwwwaaaannnntttt ttttoooo iiiinnnnccccrrrreeeemmmmeeeennnntttt tttthhhheeee
- nnnnuuuummmmbbbbeeeerrrr iiiinnnn tttthhhheeee ffffiiiilllleeee.... HHHHoooowwww ccccaaaannnn IIII ddddoooo tttthhhhiiiissss????
-
- Didn't anyone ever tell you web-page hit counters were
- useless? They don't count number of hits, they're a waste
- of time, and they serve only to stroke the writer's vanity.
- Better to pick a random number. It's more realistic.
-
- Anyway, this is what you can do if you can't help yourself.
-
- use Fcntl;
- sysopen(FH, "numfile", O_RDWR|O_CREAT) or die "can't open numfile: $!";
- flock(FH, 2) or die "can't flock numfile: $!";
- $num = <FH> || 0;
- seek(FH, 0, 0) or die "can't rewind numfile: $!";
- truncate(FH, 0) or die "can't truncate numfile: $!";
- (print FH $num+1, "\n") or die "can't write numfile: $!";
- # DO NOT UNLOCK THIS UNTIL YOU CLOSE
- close FH or die "can't close numfile: $!";
-
- Here's a much better web-page hit counter:
-
- $hits = int( (time() - 850_000_000) / rand(1_000) );
-
- If the count doesn't impress your friends, then the code
- might. :-)
-
- HHHHoooowwww ddddoooo IIII rrrraaaannnnddddoooommmmllllyyyy uuuuppppddddaaaatttteeee aaaa bbbbiiiinnnnaaaarrrryyyy ffffiiiilllleeee????
-
- If you're just trying to patch a binary, in many cases
- something as simple as this works:
-
- perl -i -pe 's{window manager}{window mangler}g' /usr/bin/emacs
-
- However, if you have fixed sized records, then you might do
- something more like this:
-
-
-
-
-
-
-
-
-
-
- Page 14 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- $RECSIZE = 220; # size of record, in bytes
- $recno = 37; # which record to update
- open(FH, "+<somewhere") || die "can't update somewhere: $!";
- seek(FH, $recno * $RECSIZE, 0);
- read(FH, $record, $RECSIZE) == $RECSIZE || die "can't read record $recno: $!";
- # munge the record
- seek(FH, $recno * $RECSIZE, 0);
- print FH $record;
- close FH;
-
- Locking and error checking are left as an exercise for the
- reader. Don't forget them, or you'll be quite sorry.
-
- HHHHoooowwww ddddoooo IIII ggggeeeetttt aaaa ffffiiiilllleeee''''ssss ttttiiiimmmmeeeessssttttaaaammmmpppp iiiinnnn ppppeeeerrrrllll????
-
- If you want to retrieve the time at which the file was last
- read, written, or had its meta-data (owner, etc) changed,
- you use the ----MMMM, ----AAAA, or ----CCCC filetest operations as documented
- in the _p_e_r_l_f_u_n_c manpage. These retrieve the age of the file
- (measured against the start-time of your program) in days as
- a floating point number. To retrieve the "raw" time in
- seconds since the epoch, you would call the stat function,
- then use _l_o_c_a_l_t_i_m_e(), _g_m_t_i_m_e(), or _P_O_S_I_X::_s_t_r_f_t_i_m_e() to
- convert this into human-readable form.
-
- Here's an example:
-
- $write_secs = (stat($file))[9];
- printf "file %s updated at %s\n", $file,
- scalar localtime($write_secs);
-
- If you prefer something more legible, use the File::stat
- module (part of the standard distribution in version 5.004
- and later):
-
- use File::stat;
- use Time::localtime;
- $date_string = ctime(stat($file)->mtime);
- print "file $file updated at $date_string\n";
-
- Error checking is left as an exercise for the reader.
-
- HHHHoooowwww ddddoooo IIII sssseeeetttt aaaa ffffiiiilllleeee''''ssss ttttiiiimmmmeeeessssttttaaaammmmpppp iiiinnnn ppppeeeerrrrllll????
-
- You use the _u_t_i_m_e() function documented in the utime entry
- in the _p_e_r_l_f_u_n_c manpage. By way of example, here's a little
- program that copies the read and write times from its first
- argument to all the rest of them.
-
-
-
-
-
-
-
- Page 15 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- if (@ARGV < 2) {
- die "usage: cptimes timestamp_file other_files ...\n";
- }
- $timestamp = shift;
- ($atime, $mtime) = (stat($timestamp))[8,9];
- utime $atime, $mtime, @ARGV;
-
- Error checking is left as an exercise for the reader.
-
- Note that _u_t_i_m_e() currently doesn't work correctly with
- Win95/NT ports. A bug has been reported. Check it
- carefully before using it on those platforms.
-
- HHHHoooowwww ddddoooo IIII pppprrrriiiinnnntttt ttttoooo mmmmoooorrrreeee tttthhhhaaaannnn oooonnnneeee ffffiiiilllleeee aaaatttt oooonnnncccceeee????
-
- If you only have to do this once, you can do this:
-
- for $fh (FH1, FH2, FH3) { print $fh "whatever\n" }
-
- To connect up to one filehandle to several output
- filehandles, it's easiest to use the _t_e_e(1) program if you
- have it, and let it take care of the multiplexing:
-
- open (FH, "| tee file1 file2 file3");
-
- Or even:
-
- # make STDOUT go to three files, plus original STDOUT
- open (STDOUT, "| tee file1 file2 file3") or die "Teeing off: $!\n";
- print "whatever\n" or die "Writing: $!\n";
- close(STDOUT) or die "Closing: $!\n";
-
- Otherwise you'll have to write your own multiplexing print
- function -- or your own tee program -- or use Tom
- Christiansen's, at
- http://www.perl.com/CPAN/authors/id/TOMC/scripts/tct.gz,
- which is written in Perl and offers much greater
- functionality than the stock version.
-
- HHHHoooowwww ccccaaaannnn IIII rrrreeeeaaaadddd iiiinnnn aaaa ffffiiiilllleeee bbbbyyyy ppppaaaarrrraaaaggggrrrraaaapppphhhhssss????
-
- Use the $\ variable (see the _p_e_r_l_v_a_r manpage for details).
- You can either set it to "" to eliminate empty paragraphs
- ("abc\n\n\n\ndef", for instance, gets treated as two
- paragraphs and not three), or "\n\n" to accept empty
- paragraphs.
-
- HHHHoooowwww ccccaaaannnn IIII rrrreeeeaaaadddd aaaa ssssiiiinnnngggglllleeee cccchhhhaaaarrrraaaacccctttteeeerrrr ffffrrrroooommmm aaaa ffffiiiilllleeee???? FFFFrrrroooommmm tttthhhheeee
- kkkkeeeeyyyybbbbooooaaaarrrrdddd????
-
- You can use the builtin getc() function for most
- filehandles, but it won't (easily) work on a terminal
-
-
-
- Page 16 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- device. For STDIN, either use the Term::ReadKey module from
- CPAN, or use the sample code in the getc entry in the
- _p_e_r_l_f_u_n_c manpage.
-
- If your system supports POSIX, you can use the following
- code, which you'll note turns off echo processing as well.
-
- #!/usr/bin/perl -w
- use strict;
- $| = 1;
- for (1..4) {
- my $got;
- print "gimme: ";
- $got = getone();
- print "--> $got\n";
- }
- exit;
-
- BEGIN {
- use POSIX qw(:termios_h);
-
- my ($term, $oterm, $echo, $noecho, $fd_stdin);
-
- $fd_stdin = fileno(STDIN);
-
- $term = POSIX::Termios->new();
- $term->getattr($fd_stdin);
- $oterm = $term->getlflag();
-
- $echo = ECHO | ECHOK | ICANON;
- $noecho = $oterm & ~$echo;
-
- sub cbreak {
- $term->setlflag($noecho);
- $term->setcc(VTIME, 1);
- $term->setattr($fd_stdin, TCSANOW);
- }
-
- sub cooked {
- $term->setlflag($oterm);
- $term->setcc(VTIME, 0);
- $term->setattr($fd_stdin, TCSANOW);
- }
-
- sub getone {
- my $key = '';
- cbreak();
- sysread(STDIN, $key, 1);
- cooked();
- return $key;
- }
-
-
-
-
- Page 17 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- }
-
- END { cooked() }
-
- The Term::ReadKey module from CPAN may be easier to use:
-
- use Term::ReadKey;
- open(TTY, "</dev/tty");
- print "Gimme a char: ";
- ReadMode "raw";
- $key = ReadKey 0, *TTY;
- ReadMode "normal";
- printf "\nYou said %s, char number %03d\n",
- $key, ord $key;
-
- For DOS systems, Dan Carson <dbc@tc.fluke.COM> reports the
- following:
-
- To put the PC in "raw" mode, use ioctl with some magic
- numbers gleaned from msdos.c (Perl source file) and Ralf
- Brown's interrupt list (comes across the net every so
- often):
-
- $old_ioctl = ioctl(STDIN,0,0); # Gets device info
- $old_ioctl &= 0xff;
- ioctl(STDIN,1,$old_ioctl | 32); # Writes it back, setting bit 5
-
- Then to read a single character:
-
- sysread(STDIN,$c,1); # Read a single character
-
- And to put the PC back to "cooked" mode:
-
- ioctl(STDIN,1,$old_ioctl); # Sets it back to cooked mode.
-
- So now you have $c. If ord($c) == 0, you have a two byte
- code, which means you hit a special key. Read another byte
- with sysread(STDIN,$c,1), and that value tells you what
- combination it was according to this table:
-
- # PC 2-byte keycodes = ^@ + the following:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 18 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- # HEX KEYS
- # --- ----
- # 0F SHF TAB
- # 10-19 ALT QWERTYUIOP
- # 1E-26 ALT ASDFGHJKL
- # 2C-32 ALT ZXCVBNM
- # 3B-44 F1-F10
- # 47-49 HOME,UP,PgUp
- # 4B LEFT
- # 4D RIGHT
- # 4F-53 END,DOWN,PgDn,Ins,Del
- # 54-5D SHF F1-F10
- # 5E-67 CTR F1-F10
- # 68-71 ALT F1-F10
- # 73-77 CTR LEFT,RIGHT,END,PgDn,HOME
- # 78-83 ALT 1234567890-=
- # 84 CTR PgUp
-
- This is all trial and error I did a long time ago, I hope
- I'm reading the file that worked.
-
- HHHHoooowwww ccccaaaannnn IIII tttteeeellllllll iiiiffff tttthhhheeeerrrreeee''''ssss aaaa cccchhhhaaaarrrraaaacccctttteeeerrrr wwwwaaaaiiiittttiiiinnnngggg oooonnnn aaaa
- ffffiiiilllleeeehhhhaaaannnnddddlllleeee????
-
- The very first thing you should do is look into getting the
- Term::ReadKey extension from CPAN. It now even has limited
- support for closed, proprietary (read: not open systems, not
- POSIX, not Unix, etc) systems.
-
- You should also check out the Frequently Asked Questions
- list in comp.unix.* for things like this: the answer is
- essentially the same. It's very system dependent. Here's
- one solution that works on BSD systems:
-
- sub key_ready {
- my($rin, $nfd);
- vec($rin, fileno(STDIN), 1) = 1;
- return $nfd = select($rin,undef,undef,0);
- }
-
- If you want to find out how many characters are waiting,
- there's also the FIONREAD ioctl call to be looked at.
-
- The _h_2_p_h tool that comes with Perl tries to convert C
- include files to Perl code, which can be required. FIONREAD
- ends up defined as a function in the _s_y_s/_i_o_c_t_l._p_h file:
-
- require 'sys/ioctl.ph';
-
- $size = pack("L", 0);
- ioctl(FH, FIONREAD(), $size) or die "Couldn't call ioctl: $!\n";
- $size = unpack("L", $size);
-
-
-
- Page 19 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- If _h_2_p_h wasn't installed or doesn't work for you, you can
- _g_r_e_p the include files by hand:
-
- % grep FIONREAD /usr/include/*/*
- /usr/include/asm/ioctls.h:#define FIONREAD 0x541B
-
- Or write a small C program using the editor of champions:
-
- % cat > fionread.c
- #include <sys/ioctl.h>
- main() {
- printf("%#08x\n", FIONREAD);
- }
- ^D
- % cc -o fionread fionread
- % ./fionread
- 0x4004667f
-
- And then hard-code it, leaving porting as an exercise to
- your successor.
-
- $FIONREAD = 0x4004667f; # XXX: opsys dependent
-
- $size = pack("L", 0);
- ioctl(FH, $FIONREAD, $size) or die "Couldn't call ioctl: $!\n";
- $size = unpack("L", $size);
-
- FIONREAD requires a filehandle connected to a stream,
- meaning sockets, pipes, and tty devices work, but _n_o_t files.
-
- HHHHoooowwww ddddoooo IIII ddddoooo aaaa ttttaaaaiiiillll ----ffff in perl?
-
- First try
-
- seek(GWFILE, 0, 1);
-
- The statement seek(GWFILE, 0, 1) doesn't change the current
- position, but it does clear the end-of-file condition on the
- handle, so that the next <GWFILE> makes Perl try again to
- read something.
-
- If that doesn't work (it relies on features of your stdio
- implementation), then you need something more like this:
-
- for (;;) {
- for ($curpos = tell(GWFILE); <GWFILE>; $curpos = tell(GWFILE)) {
- # search for some stuff and put it into files
- }
- # sleep for a while
- seek(GWFILE, $curpos, 0); # seek to where we had been
- }
-
-
-
-
- Page 20 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- If this still doesn't work, look into the POSIX module.
- POSIX defines the _c_l_e_a_r_e_r_r() method, which can remove the
- end of file condition on a filehandle. The method: read
- until end of file, _c_l_e_a_r_e_r_r(), read some more. Lather,
- rinse, repeat.
-
- HHHHoooowwww ddddoooo IIII _d_u_p() a filehandle in Perl?
-
- If you check the open entry in the _p_e_r_l_f_u_n_c manpage, you'll
- see that several of the ways to call _o_p_e_n() should do the
- trick. For example:
-
- open(LOG, ">>/tmp/logfile");
- open(STDERR, ">&LOG");
-
- Or even with a literal numeric descriptor:
-
- $fd = $ENV{MHCONTEXTFD};
- open(MHCONTEXT, "<&=$fd"); # like fdopen(3S)
-
- Note that "<&STDIN" makes a copy, but "<&=STDIN" make an
- alias. That means if you close an aliased handle, all
- aliases become inaccessible. This is not true with a copied
- one.
-
- Error checking, as always, has been left as an exercise for
- the reader.
-
- HHHHoooowwww ddddoooo IIII cccclllloooosssseeee aaaa ffffiiiilllleeee ddddeeeessssccccrrrriiiippppttttoooorrrr bbbbyyyy nnnnuuuummmmbbbbeeeerrrr????
-
- This should rarely be necessary, as the Perl _c_l_o_s_e()
- function is to be used for things that Perl opened itself,
- even if it was a dup of a numeric descriptor, as with
- MHCONTEXT above. But if you really have to, you may be able
- to do this:
-
- require 'sys/syscall.ph';
- $rc = syscall(&SYS_close, $fd + 0); # must force numeric
- die "can't sysclose $fd: $!" unless $rc == -1;
-
-
- WWWWhhhhyyyy ccccaaaannnn''''tttt IIII uuuusssseeee """"CCCC::::\\\\tttteeeemmmmpppp\\\\ffffoooooooo"""" iiiinnnn DDDDOOOOSSSS ppppaaaatttthhhhssss???? WWWWhhhhaaaatttt ddddooooeeeessssnnnn''''tttt
- ````CCCC::::\\\\tttteeeemmmmpppp\\\\ffffoooooooo....eeeexxxxeeee```` wwwwoooorrrrkkkk????
-
- Whoops! You just put a tab and a formfeed into that
- filename! Remember that within double quoted strings
- ("like\this"), the backslash is an escape character. The
- full list of these is in the section on _Q_u_o_t_e _a_n_d _Q_u_o_t_e-_l_i_k_e
- _O_p_e_r_a_t_o_r_s in the _p_e_r_l_o_p manpage. Unsurprisingly, you don't
- have a file called "_c:(tab)_e_m_p(formfeed)oo" or
- "_c:(tab)_e_m_p(formfeed)oo.exe" on your DOS filesystem.
-
-
-
-
- Page 21 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- Either single-quote your strings, or (preferably) use
- forward slashes. Since all DOS and Windows versions since
- something like MS-DOS 2.0 or so have treated / and \ the
- same in a path, you might as well use the one that doesn't
- clash with Perl -- or the POSIX shell, ANSI C and C++, awk,
- Tcl, Java, or Python, just to mention a few.
-
- WWWWhhhhyyyy ddddooooeeeessssnnnn''''tttt _g_l_o_b("*.*") get all the files?
-
- Because even on non-Unix ports, Perl's glob function follows
- standard Unix globbing semantics. You'll need glob("*") to
- get all (non-hidden) files. This makes _g_l_o_b() portable.
-
- WWWWhhhhyyyy ddddooooeeeessss PPPPeeeerrrrllll lllleeeetttt mmmmeeee ddddeeeelllleeeetttteeee rrrreeeeaaaadddd----oooonnnnllllyyyy ffffiiiilllleeeessss???? WWWWhhhhyyyy ddddooooeeeessss ----iiii
- clobber protected files? Isn't this a bug in Perl?
-
- This is elaborately and painstakingly described in the "Far
- More Than You Ever Wanted To Know" in
- http://www.perl.com/CPAN/doc/FMTEYEWTK/file-dir-perms .
-
- The executive summary: learn how your filesystem works. The
- permissions on a file say what can happen to the data in
- that file. The permissions on a directory say what can
- happen to the list of files in that directory. If you
- delete a file, you're removing its name from the directory
- (so the operation depends on the permissions of the
- directory, not of the file). If you try to write to the
- file, the permissions of the file govern whether you're
- allowed to.
-
- HHHHoooowwww ddddoooo IIII sssseeeelllleeeecccctttt aaaa rrrraaaannnnddddoooommmm lllliiiinnnneeee ffffrrrroooommmm aaaa ffffiiiilllleeee????
-
- Here's an algorithm from the Camel Book:
-
- srand;
- rand($.) < 1 && ($line = $_) while <>;
-
- This has a significant advantage in space over reading the
- whole file in. A simple proof by induction is available
- upon request if you doubt its correctness.
-
- AAAAUUUUTTTTHHHHOOOORRRR AAAANNNNDDDD CCCCOOOOPPPPYYYYRRRRIIIIGGGGHHHHTTTT
- Copyright (c) 1997, 1998 Tom Christiansen and Nathan
- Torkington. All rights reserved.
-
- When included as an integrated part of the Standard
- Distribution of Perl or of its documentation (printed or
- otherwise), this works is covered under Perl's Artistic
- Licence. For separate distributions of all or part of this
- FAQ outside of that, see the _p_e_r_l_f_a_q manpage.
-
- Irrespective of its distribution, all code examples here are
-
-
-
- Page 22 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLFFFFAAAAQQQQ5555((((1111))))
-
-
-
- public domain. You are permitted and encouraged to use this
- code and any derivatives thereof in your own programs for
- fun or for profit as you see fit. A simple comment in the
- code giving credit to the FAQ would be courteous but is not
- required.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 23 (printed 10/23/98)
-
-
-
-